// QPART change here

/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
 * Copyright (c) 1997 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the Computer Systems
 *	Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/* Ported from CMU/Monarch's code, nov'98 -Padma.*/

/* -*- c++ -*-
   priqueue.cc

   A simple priority queue with a remove packet function
   $Id: priqueue.cc,v 1.5 2003/02/21 00:40:22 haldar Exp $
   */
// 1. QPART
/*
#include <object.h>
#include <queue.h>
#include <drop-tail.h>*/
// end 1
#include <packet.h>
#include <cmu-trace.h>
//#include <mac/ll.h>
//#include <mac/mac-802_11.h>
//#include <mac/mac-timers.h>
// 2. QPART
#include "../aodv/aodv.h"
#include "../aodv/aodv_packet.h"


#include <priqueue.h>
#include <random.h>

#define time_interval 0.1


#define delta 0.002		//2 milli seconde
#define Pmax 250		//Pmax
//pile *MaListe = new pile;
//MaListe = malloc(sizeof(MaListe));
//MaListe = NIL;

int tableau [10];
double time = 0;
// end 2
typedef int (*PacketFilter)(Packet *, void *);
PriQueue_List PriQueue::prhead = { 0 };
// 3. QPART
Prio *prior = (Prio *)malloc(sizeof(Prio));
int i = 1;
// end 3

static class PriQueueClass : public TclClass {
	//friend class PriorTimer;
public:
  PriQueueClass() : TclClass("Queue/DropTail/PriQueue") {}
  TclObject* create(int, const char*const*) {

  //prior->next = NULL;
    return (new PriQueue);
  }
} class_PriQueue;
/*
void PriQueue :: set_update_timer()
{
	ph_.resched(time_interval);
}
*/
PriQueue::PriQueue() : DropTail(){//, ph_(this){


        bind("Prefer_Routing_Protocols", &Prefer_Routing_Protocols);
	LIST_INSERT_HEAD(&prhead, this, link);
	//ph_.resched(time_interval);
}

int
PriQueue::command(int argc, const char*const* argv)
{
  if (argc == 2 && strcasecmp(argv[1], "reset") == 0)
    {
      Terminate();
      //FALL-THROUGH to give parents a chance to reset
    }
   return DropTail::command(argc, argv);
}


/*void
PriorTimer::expire(Event e)
{
       //q->do_something_from_public_or_protected interface
       resched(time_interval);
}
*/

/*
void
PriorTimer::TimerHandler() {
//...other code...
//printf("dans la fonction du timer \n");
// UpdatePrio(p);
ph_.resched(time_interval);
}
*/


/*============================================================================================
bool PriQueue::lookupprio(Prio *p, int fid)
void PriQueue::insertprio(Prio **p, int fid, int prio)
void PriQueue::afficheprio(Prio *p)
Prio PriQueue::findprio(Prio *p, int fid)
=============================================================================================*/
// 4. QPART
bool lookupprio(Prio *p, int fid)
{
Prio *pcour = (Prio *)malloc(sizeof(Prio));
pcour = p;

	if(pcour==NULL)
		return false;

	while(pcour)
	{
		if (pcour->fid == fid)
		{
                return true;
		}
	pcour=pcour->next;
	}
	return false;
}



Prio findprio(Prio *p, int fid)
{
Prio *pcour = (Prio *)malloc(sizeof(Prio));
//if(!pcour) return;	//Si l'allocation a �chou�e
*pcour = *p;
	while(pcour != NULL)
	{
		if (pcour->fid == fid)
		{
		return (*pcour);
		}
	pcour=pcour->next;			//EN PRINCIPE AVEC*
	}
	//return false;
    //      }
}


void insertprio(Prio **p, int fid, int prio, ns_addr_t src, ns_addr_t dst)	//ns_addr_t src, ns_addr_t dst
{
		Prio *pcour = (Prio *)malloc(sizeof(Prio));
		   //if(!pcour) return;	//Si l'allocation a �chou�e
		   pcour = *p;
		if (lookupprio(*p, fid)){ 	//si le fid  existe  deja alorscalcul_seuil
		while (pcour->fid != fid)
			{
			pcour = pcour->next;
			}
		pcour->prio = prio;
		pcour->src = src;
		pcour->dst = dst;
		} else 			//si le fid existe il suffit de mettre a jour sa periorit�
		   {
			//printf("fid n existe pas!!! je le cree\n");
			while (pcour->next != NULL)
				{
				pcour = pcour->next;
				}
			Prio *e = (Prio *)malloc(sizeof(Prio));
			//if(!e) return;	//Si l'allocation a �chou�e
			e->fid=fid;
			e->prio=prio;
			e->src=src;
			e->dst=dst;
			e->next=NULL;
			pcour->next = e;
		   }
}


void afficheprio(Prio *p)
{
Prio *pcour = (Prio *)malloc(sizeof(Prio));
*pcour = *p;
	while(pcour)
	{
		printf("FILE      fid  == %d  prio == %d\n",pcour->fid,pcour->prio);
		pcour=pcour->next;
		//printf("");
		//p=p->next;
		printf("********\n");
	}
	printf("*****************************\n\n");
}
// end 4



/*---------------------------------------------------------------------------------------
	Cette fonction permet d'incrementer la valeur de la priorite d'un paquet
	et retourne la nouvelle valeur de priorit�
----------------------------------------------------------------------------------------*/
/*void
PriQueue::UpdatePrio(Packet *p)
{
int PrioQos=0;
	int precQos=0;
	int PrioBe=0;
	int precBe=0;
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
set_update_timer();
//printf("UPDATE PRIO DS PEQUEUE!!!\n");
	if (ih->fid_ > 10)		//QOS
	   {
		PrioQos = ih->prio_;
		if (PrioQos < Pmax)
		 {
		  PrioQos = PrioQos + 1;
		  precQos = PrioQos;
		 }
		if (PrioQos >= Pmax)
		 {
		  PrioQos = Pmax;
		 }

		ih->prio_= PrioQos ;
		printf("prio QOS de fid %d  (uid=%d)    == %d\n", ih->fid_, ch->uid_, ih->prio_);
	    }
	if ( (ih->fid_ <= 10) && (ih->fid_ > 0) )
	    {
		PrioBe = ih->prio_;
		if (PrioBe < Pmax)
		 {
		  PrioBe = PrioBe + 1;
		  precBe = PrioBe;
		 }
		if (PrioBe >= Pmax)
		 {
		  PrioBe = Pmax;
		 }

		ih->prio_= PrioBe;
		printf("prio BE de fid %d  (uid=%d)    == %d\n", ih->fid_, ch->uid_, ih->prio_);
	    }
//ph.resched(time_interval);
double now = Scheduler::instance().clock();
struct hdr_ip *ih = HDR_IP(p);
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ll *lh = HDR_LL(p);
//update(p);
	int PrioQos=0;
	int precQos=0;
	int PrioBe=0;
	int precBe=0;
	int uid=ch->uid_;
	int seq=lh->seqno_;
	//ns_addr_t src=ih->src_;
	//ns_addr_t dst=ih->dst_;
	double tim = lh->sendtime_;

//=====================================================================

//=====================================================================

	if (ih->fid_ > 10)		//QOS
	   {
		PrioQos = ih->prio_;
		if (PrioQos < Pmax)
		 {
		  PrioQos = PrioQos + 1;
		  precQos = PrioQos;
		 }
		if (PrioQos >= Pmax)
		 {
		  PrioQos = Pmax;
		 }

		ih->prio_= PrioQos ;
		tableau[ih->fid_]= PrioQos;
		//printf("PrioQos = %d   et uid = %d   et src = %d  et dst = %d\n",PrioQos, uid, ih->saddr(), ih->daddr());
		return(PrioQos);

	   }
	else				//BE
	{
	  if ( (ih->fid_ <= 10) && (ih->fid_ > 0) )
		{
		PrioBe = ih->prio_;
		if (PrioBe < Pmax)
		 {
		  PrioBe = PrioBe + 1;
		  precBe = PrioBe;
		 }
		if (PrioBe >= Pmax)
		 {
		  PrioBe = Pmax;
		 }

		ih->prio_= PrioBe;
		tableau[ih->fid_]= PrioBe ;
		//printf("PrioBe = %d     et uid = %d et src =%d  et dst = %d\n",PrioBe,uid, ih->saddr(), ih->daddr());
		//printf("val be ds tableau = %d\n",tableau[ih->fid_]);
		return(PrioBe);
		}
	}
//ph.resched(time_interval);

}
*/
/*-----------------------------------------------------------------------------------------------
	cette fontion pemet de calculer le seuil d admission et retourne la valeur du seuil
------------------------------------------------------------------------------------------------*/
/*float
PriQueue::calcul_seuil(Packet *p)
{
	struct hdr_ip *ih = HDR_IP(p);
	float Tk=0.0001;
	int Pk=0;	//le seuil le plus ptit
	Pk = ih->prio_;
	Tk = (Pmax - Pk) * teta + nu; 		//formule du seuil d admission
	//printf("le seuil  = %f\n", Tk);
	ih->seuil_ = Tk;
	return(Tk);
}*/
/*-----------------------------------------------------------------------------------------------
	cette fontion pemet de retourner une valeur aleatoire entre deux valeurs
------------------------------------------------------------------------------------------------*/
/*
float myRandom(float m, float n)
{
	float t=0;
	t=Random::uniform();
	return(t*(n - m) + m);
}*/

/*--------------------------------------------------------------------------------------------
		cette fonction permet de retourner un float representant un temps aleatoire
		avant de dafficheprio(prior);ecider : rejeter ou non le flux consid�r�
---------------------------------------------------------------------------------------------*/
/*
float defer_time(Packet *p)
{
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_ip *ih = HDR_IP(p);
	int defTime = 0;			//initialisation on suppose que
	float t1=0;
	float t2=0;
	float rand=0;			//valeur aleatoire entre t1 et t2;
	//double a=0;
	t1 = (ih->prio_) * delta;
	t2 = (ih->prio_ + 1) * delta;
	printf("t1  %f\n",t1);
	printf("t2  %f\n",t2);
	//rand = (Random::random() * (t2-t1))+t1;	//retourner une valeur random entre t1 et t2
	rand = myRandom(t1, t2);
	printf("random  entre t1 et t2 ds defer_time = %f\n",rand);
	return(rand);

}
*/

void
PriQueue::recv(Packet *p, Handler *h)
{
 //ph.resched(time_interval);

struct hdr_cmn *ch = HDR_CMN(p);
//ph.resched(time_interval);
//***************************************************************
/*if (ch->direction_ == -1)
    {
    printf("allooooooooooooooooo\n");
    printf("fn == %d\n",ch->Fn_);
    //printf("le idle time de la station emetrice numero  == %d  est de valeur  ==  %f\n",ch->prev_hop_, ch->Fn_);
    }*/
//**************************************************************
//---------------------------------------------------------

//---------------------------------------------------------

//printf("a");

//UpdatePrio(p);
// 5. QPART
	beLength=0;
	qosLength=0;
bool test=true;
struct hdr_ip *ih = HDR_IP(p);

//if(Prefer_Routing_Protocols) {
	if ( (ih->fid_ <= 10) && (ih->fid_ > 0) )
	  {
		beLength = q_->len_;
		ih->qn_ = beLength;
		Queue::recv(p, h);
	  }

	else //if (ih->fid_ > 10)		//QOS
	{

		qosLength = q_->len_;
		ih->qn_ = qosLength;



		recvHighPriority(p, h);
		//uptarget_->recv(p,h);
		}

	//}
	//}

/*
  if(Prefer_Routing_Protocols) {
  printf("\n\n\n\n88888888888888888888888888888888888888888888888888888888888888888ROUTING\n\n\n\n");

                switch(ch->ptype()) {
		case PT_DSR:
		case PT_MESSAGE:
                case PT_TORA:
                case PT_AODV:
                        recvHighPriority(p, h);
                        //break;

                default:
                        Queue::recv(p, h);
                }
        }
        else {
                Queue::recv(p, h);
		}
*/
        //} else {printf("\n\n\n2222222222222222222222222222222222222222222222222222222\n\n\n\n");}

//int tst1= 0;
//float tst2= 0;

//double now = Scheduler::instance().clock();
//if (now == (time + 0.1))
//{
//Update(p);
//ih->prio_ = UpdatePrio(p);
//tst1=ih->prio_;
//printf("tesssssssssssst = %d \n", tst1);
//tst2 = defer_time(p);
//printf("te222222222222t = %f \n", tst2);
//UpdatePrio(p);
//time = now;
//}
//printf("timme = %f\n", now);
//time = now;
//float s;
//s = calcul_seuil(p);
//printf("seuil = %f\n",s);

//-------------------------------------------------------------

//test=lookupprio(prior,ih->fid_);

	//if( (test == false) )
          // {

		//insertprio(&prior,ih->fid_,ih->prio_, ih->src(), ih->dst());	//, ih->src_, ih->dst_
           //}
//afficheprio(prior);
//-------------------------------------------------------------

	//printf("FFFFFFFFnnnnnnnnnn ds priqueue  ==  %f\n", ch->Fn_);

// end 5

}



void
PriQueue::recvHighPriority(Packet *p, Handler *)
  // insert packet at front of queue
{
//struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);
// 6. QPART
bool test=false;
struct hdr_ip *ih = HDR_IP(p);

//UpdatePrio(p);
// end 6


	q_->enqueHead(p);
	// 7. QPART
//	float s;
//s = calcul_seuil(p);
//----------------------------------------------------------------------------------------------
   /*  if(rp->rp_type == AODVTYPE_RREP)
                  {
		   printf("+++++++++++++++++++++++++++++++le rp_false_rrep ds priqueue == %d",rp->rp_false_RREP);
                   if (rp->rp_false_RREP == 1)
                   {
		   printf("RECEPTION DE FALSE RREP DANS PRIQUEUE.CC");
                   //printf("OK LL : RECV FALSE RREP %f\n",rp->rp_bplibre);
                  /* DropTail::priqueue = 1;
                   DropTail::bplibre = rp->rp_bplibre;
                   //printf("Bande Passante BE %f\n",rp->rp_timestamp);
                   DropTail::bpBE = rp->rp_timestamp;
                   DropTail::nbFlux_be = rp->rp_hop_count;
                   // Drop Packet
                   Packet *to_drop = q_->lookup(q_->length()-1);
                   q_->remove(to_drop);
                   drop(to_drop);*/
                   //}
                  //}
//--------------------------------------------------------------------------------------------


//test=lookupprio(prior,ih->fid_);
//	if( (test == false) )
  //         {
  		insertprio(&prior,ih->fid_,ih->prio_, ih->src(), ih->dst());	//, ih->src_, ih->dst_
    //       }
//afficheprio(prior);
//-------------------
  		// end 7

	if (q_->length() >= qlim_)
    {
      Packet *to_drop = q_->lookup(q_->length()-1);
      q_->remove(to_drop);
      drop(to_drop);
    }

  if (!blocked_) {
    /*
     * We're not blocked.  Get a packet and send it on.
     * We perform an extra check because the queue
     * might drop the packet even if it was
     * previously empty!  (e.g., RED can do this.)
     */
    p = deque();
    if (p != 0) {
      blocked_ = 1;
      target_->recv(p, &qh_);
    }
  }
}

void
PriQueue::filter(PacketFilter filter, void * data)
  // apply filter to each packet in queue,
  // - if filter returns 0 leave packet in queue
  // - if filter returns 1 remove packet from queue
{
  int i = 0;
  while (i < q_->length())
    {
      Packet *p = q_->lookup(i);
      if (filter(p,data))
	{
	  q_->remove(p); // decrements q len
	}
      else i++;
    }
}

Packet*
PriQueue::filter(nsaddr_t id)
{
	Packet *p = 0;
	Packet *pp = 0;
	struct hdr_cmn *ch;

	for(p = q_->head(); p; p = p->next_) {
		ch = HDR_CMN(p);
		if(ch->next_hop() == id)
			break;
		pp = p;
	}

	/*
	 * Deque Packet
	 */
	if(p) {
		if(pp == 0)
			q_->remove(p);
		else
			q_->remove(p, pp);
	}
	return p;
}

/*
 * Called at the end of the simulation to purge the IFQ.
 */
void
PriQueue::Terminate()
{
	Packet *p;
	while((p = deque())) {
		drop(p, DROP_END_OF_SIMULATION);
		//drop(p);

	}
}




